using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PropSys;
using System;
using UnityEngine.InputSystem;

public class MainCtrl : MonoBehaviour
{

    private PfmFSM _pfmFSM;
    private PropModule _PM;
    private SkillModule _SM;
    private Animator _animator;
    private bool _isSkillEnhanced;
    private MovType _curMov;
    public int _curMovTimer;
    private Rigidbody _rb;
    private Vector3 _dir;
    private Quaternion _localOri;

    [Header("Settings")]
    public int _iptInterval;
    public float _jumpForce;
    public float _gravityStrengthen;

    private void Start()
    {
        _rb = GetComponent<Rigidbody>();
        _animator = GetComponent<Animator>();
        _PM = GetComponent<PropModule>();
        _SM = GetComponent<SkillModule>();
        _pfmFSM = new PfmFSM(this, _iptInterval);
        _dir = Vector3.zero;
    }

    private void Update()
    {
        _pfmFSM._curSt.LogicUpd();
        _rb.AddForce(Vector3.down * _gravityStrengthen, ForceMode.Acceleration);
    }

    #region Prop Sys
    public void RegVal(PropType pt, PropReg pr, string key, Func<float> val) { _PM.RegVal(pt, pr, key, val); }
    public void UregVal(PropType pt, PropReg pr, string key) { _PM.UregVal(pt, pr, key); }

    //HP SP MP
    #endregion
    #region Ipt
    public void IptDir(InputAction.CallbackContext context)
    {
        _pfmFSM._curSt.IptDir(context.ReadValue<Vector2>());
    }

    public void IptLT(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started) _isSkillEnhanced = true;
        else if (context.phase == InputActionPhase.Canceled) _isSkillEnhanced = false;
    }

    public void IptLB(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started || context.phase == InputActionPhase.Performed)
        {
            _pfmFSM._curSt.Blk();
        }
        else if (context.phase == InputActionPhase.Canceled) _pfmFSM._curSt.CancelBlk();
    }

    public void IptRT(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started)
        {
            _curMov = MovType.Dodge;
            _pfmFSM._curSt.Dodge();
        }
        else if (context.phase == InputActionPhase.Canceled) _pfmFSM._curSt.CancelDash();
    }

    public void IptRB(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started && IsGround()) _pfmFSM._curSt.Air();
    }

    public void IptX(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started)
        {
            _curMov = MovType.West;
            _pfmFSM._curSt.PfmSkill();
        }
    }

    public void IptY(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started)
        {
            _curMov = MovType.North;
            _pfmFSM._curSt.PfmSkill();
        }
    }

    public void IptA(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started)
        {
            _curMov = MovType.South;
            _pfmFSM._curSt.PfmSkill();
        }
    }

    public void IptB(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started)
        {
            _curMov = MovType.East;
            _pfmFSM._curSt.PfmSkill();
        }
    }
    #endregion
    #region Action
    public void Jump()
    {
        _rb.AddForce(Vector3.up * _jumpForce, ForceMode.Impulse);
    }

    public void Move()
    {
        if (!IsGround()) return;
        if (_dir == Vector3.zero)
        {
            _rb.velocity = Vector3.up * _rb.velocity.y;
            return;
        }
        transform.rotation = _localOri * GameManager.Instance._curCameraOri;
        _rb.velocity = GameManager.Instance._curCameraOri * new Vector3(_dir.x * _PM._spd.Val, _rb.velocity.y, _dir.z * _PM._spd.Val);
    }

    public void StopMove()
    {
        GetDri(Vector2.zero);
        Move();//move at Vector3.zero dir
    }

    public void PlayAnim(string animName) { _animator.Play(animName); }
    #endregion
    #region Server
    public void GetDri(Vector2 vec)
    {
        _dir = new Vector3(vec.x, 0, vec.y).normalized;
        float ang = Vector3.Angle(Vector3.forward, _dir);
        float w = Vector3.Cross(Vector3.forward, _dir).y;
        if (w < 0) ang = -ang;
        _localOri = Quaternion.AngleAxis(ang, Vector3.up);
    }

    public void SetIdle()
    {
        StopMove();
        _rb.useGravity = true;
        _animator.Play("Idle");
    }

    public void UseGravity() { _rb.useGravity = true; }
    public void Weightless() { _rb.useGravity = true; }

    public bool IsGround()
    {
        RaycastHit hitInfo;
        Physics.Raycast(transform.position, Vector3.down * 0.55f, out hitInfo, 1);
        return hitInfo.collider != null && !hitInfo.collider.isTrigger;
    }
    #endregion

    public void PrepareMov()
    {
        switch (_curMov)
        {
            case MovType.Dodge:
                _curMovTimer = _SM._movDuras["Dodge"];
                break;
            case MovType.South:
                StopMove();
                _curMovTimer = _SM._movDuras[_SM._skillKeys[0]];
                break;
            case MovType.West:
                StopMove();
                _curMovTimer = _SM._movDuras[_SM._skillKeys[1]];
                break;
            case MovType.North:
                StopMove();
                _curMovTimer = _SM._movDuras[_SM._skillKeys[2]];
                break;
            case MovType.East:
                StopMove();
                _curMovTimer = _SM._movDuras[_SM._skillKeys[3]];
                break;
            default:
                break;
        }
    }

    public void PfmCurMov()
    {
        switch (_curMov)
        {
            case MovType.Dodge:
                _rb.velocity = Vector3.zero;
                Vector3 dir = (GameManager.Instance._curCameraOri * new Vector3(_dir.x, 0, _dir.z)).normalized;
                _rb.AddForce(dir * 10, ForceMode.Impulse);
                break;
            case MovType.South:
                if (_isSkillEnhanced) _animator.Play(_SM._skillKeys[0]);
                else _animator.Play(_SM._skillKeys[0]);
                break;
            case MovType.West:
                if (_isSkillEnhanced) _animator.Play(_SM._skillKeys[1]);
                else _animator.Play(_SM._skillKeys[1]);
                break;
            case MovType.North:
                if (_isSkillEnhanced) _animator.Play(_SM._skillKeys[2]);
                else _animator.Play(_SM._skillKeys[2]);
                break;
            case MovType.East:
                if (_isSkillEnhanced) _animator.Play(_SM._skillKeys[3]);
                else _animator.Play(_SM._skillKeys[3]);
                break;
            default:
                break;
        }
    }
}
